package utilities;

import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import javax.imageio.ImageIO;

/**
 * Class handling the loading of images from the files
 */

public class ImageLoader
{
    private final static String IMAGE_DIR="Images/";

    private HashMap imageMap;

    private GraphicsConfiguration gc;

    //Creates a new ImageLoader
    public ImageLoader()
    {
        initImageLoader();
    }

    //Creates a new ImageLoader and loades images from the specified file
    public ImageLoader(String file)
    {
        initImageLoader();
        loadImagesFile(file);
    }

    //Initializes the newly created ImageLoader, creating the HashMap for storing the image references
    public void initImageLoader()
    {
        imageMap=new HashMap();
        GraphicsEnvironment ge=GraphicsEnvironment.getLocalGraphicsEnvironment();
        gc=ge.getDefaultScreenDevice().getDefaultConfiguration();
    }

    //Gets the images stored under a certain <name>
    public ArrayList getImages(String name)
    {
        ArrayList imList=(ArrayList)imageMap.get(name);
        if (imList==null)
        {
            System.out.println("No image(s) stored under " + name);
            return null;
        }

        System.out.println("Returning all images stored under " + name);
        return imList;
    }

    //Loads the file listing the images in for reading
    private void loadImagesFile(String file)
    {
        String path=IMAGE_DIR+file;
        System.out.println("Reading file: "+path);
        try
        {
            InputStream in=this.getClass().getResourceAsStream(path);
            BufferedReader br=new BufferedReader(new InputStreamReader(in));
            String line;
            char ch;
            while((line=br.readLine())!=null)
            {
                if(line.length()==0)  // blank line
                    continue;
                if(line.startsWith("//"))   // comment
                    continue;
                ch=Character.toLowerCase(line.charAt(0));
                if (ch=='o')  // a single image
                    getFileNameImage(line);
                else
                    //if (ch=='n')  // a numbered sequence of images
                        //getNumberedImages(line);
                    //else
                        if (ch=='s')  // an images strip
                            getStripImages(line);
                        //else
                            //if (ch=='g') // a group of images
                                //getGroupImages(line);
                            else
                                System.out.println("Do not recognize line: "+line);
            }
            br.close();
        }
        catch (IOException e)
        {
            System.out.println("Error reading file: " + path);
            System.exit(1);
        }
    }

    //-------------------------------------------------------------------
    //Loading single image files-----------------------------------------
    //-------------------------------------------------------------------

    //Gets a single image from the file
    //Single images are marked with 'o' in the text file
    private void getFileNameImage(String line)
    {
        StringTokenizer tokens=new StringTokenizer(line);
        if (tokens.countTokens()!=2)
            System.out.println("Wrong no. of arguments for " + line);
        else
        {
            tokens.nextToken();
            System.out.print("o Line: ");
            loadSingleImage(tokens.nextToken());
        }
    }

    //Loads a single image file into the HashMap
    public boolean loadSingleImage(String filename)
    {
        String name=getPrefix(filename);

        if (imageMap.containsKey(name))
        {
            System.out.println( "Error: "+name+"already used");
            return false;
        }

        BufferedImage bi=loadImage(filename);
        if (bi!=null)
        {
            ArrayList imList=new ArrayList();
            imList.add(bi);
            imageMap.put(name,imList);
            System.out.println("  Stored "+name+"/"+filename);
            return true;
        }
        else
            return false;
    }

    //-------------------------------------------------------------------
    //Loading image strip files-----------------------------------------
    //-------------------------------------------------------------------

    private void getStripImages(String line)
    /*Gets a strip image (series of images) from the file
    Strip images are marked with 's' in the text file*/
    {
        StringTokenizer tokens=new StringTokenizer(line);

        if (tokens.countTokens()!=3)
            System.out.println("Wrong no. of arguments for "+line);
        else
        {
            tokens.nextToken();
            System.out.print("s Line: ");

            String filename=tokens.nextToken();
            int number=-1;
            try
            {
                number=Integer.parseInt(tokens.nextToken());
            }
            catch(Exception e)
            {
                System.out.println("Number is incorrect for "+line);
            }

            loadStripImages(filename,number);
        }
    }

    public int loadStripImages(String filename, int number)
    /*Loads a strip image file into the HashMap*/
    {
        String name=getPrefix(filename);
        if (imageMap.containsKey(name))
        {
            System.out.println( "Error: " + name + "already used");
            return 0;
        }

        BufferedImage[] strip=loadStripImageArray(filename,number);
        if (strip==null)
            return 0;

        ArrayList imList=new ArrayList();
        int loadCount=0;
        System.out.print("  Adding "+name+"/"+filename+"... ");
        for (int i=0;i<strip.length;i++)
        {
            loadCount++;
            imList.add(strip[i]);
            System.out.print(i + " ");
        }
        System.out.println();

        if (loadCount==0)
            System.out.println("No images loaded for " + name);
        else
        imageMap.put(name,imList);

        return loadCount;
    }

    // extract name before '.' of filename
    private String getPrefix(String filename)
    {
        int pos;
        if ((pos=filename.lastIndexOf("."))==-1)
        {
            System.out.println("No prefix found for filename: "+filename);
            return filename;
        }
        else
            return filename.substring(0,pos);
    }

    
    public BufferedImage getImage(String name)
    {
        ArrayList imList=(ArrayList)imageMap.get(name);
        if (imList==null)
        {
            System.out.println("No image(s) stored under " + name);
            return null;
        }
        return (BufferedImage) imList.get(0);
    }

    public BufferedImage getImage(String name,int pos)
    {
        ArrayList imList=(ArrayList)imageMap.get(name);
        if (imList==null)
        {
            System.out.println("No image(s) stored under " + name);
            return null;
        }

        int size=imList.size();
        if (pos<0)
        {
            return (BufferedImage)imList.get(0);
        }
        else
            if (pos>=size)
            {
                int newPos=pos%size;
                return (BufferedImage)imList.get(newPos);
            }
        return (BufferedImage)imList.get(pos);
    }

    public boolean isLoaded(String name)
    {
        ArrayList imList=(ArrayList)imageMap.get(name);
        if (imList==null)
            return false;
        return true;
    }

    public int numberOfImages(String name)
    {
        ArrayList imList=(ArrayList)imageMap.get(name);
        if (imList==null)
        {
            return 0;
        }
        return imList.size();
    }

    //Load the image from <filename>, returning it as a BufferedImage
    //which is compatible with the graphics device being used.
    //Uses ImageIO.
    public BufferedImage loadImage(String filename)
    {
        try
        {
            BufferedImage bi=ImageIO.read(getClass().getResource(IMAGE_DIR+filename));
            int transparency=bi.getColorModel().getTransparency();
            BufferedImage copy=gc.createCompatibleImage(bi.getWidth(),bi.getHeight(),transparency);
            Graphics2D g2d=copy.createGraphics();
            g2d.drawImage(bi,0,0,null);
            g2d.dispose();
            return copy;

        }
        catch(IOException e)
        {
            System.out.println("Load Image error for "+IMAGE_DIR+"/"+filename+":\n"+e);
            return null;
        }
    }

    //Loads <number> of strip images from <filename>, returning them as a BufferedImages
    public BufferedImage[] loadStripImageArray(String filename, int number)
    {
        if (number<=0)
        {
            System.out.println("number <= 0; returning null");
            return null;
        }

        BufferedImage stripIm;
        if ((stripIm=loadImage(filename))==null)
        {
            System.out.println("Returning null");
            return null;
        }

        int imWidth=(int)stripIm.getWidth()/number;
        int height=stripIm.getHeight();
        int transparency=stripIm.getColorModel().getTransparency();

        BufferedImage[] strip=new BufferedImage[number];
        Graphics2D stripGC;

        for (int i=0;i<number;i++)
        {
            strip[i]=gc.createCompatibleImage(imWidth,height,transparency);
            stripGC=strip[i].createGraphics();
            stripGC.drawImage(stripIm,0,0,imWidth,height,i*imWidth,0,(i*imWidth)+imWidth,height,null);
            stripGC.dispose();
        }
        return strip;
    }
    
}
